/*
	A small game about 赌博 for run match
	cody by hopy
	copyright 2015-08-10
*/

#include <sys/time.h>
#include <gnome.h>
#include "comm.h"
#include "rec.h"

#define UI_PATH "./run.ui"
#define MAIN_WINDOW "window"
#define BTN_RUN "btn_run"
#define BTN_BEST "btn_best"
#define BTN_SET_CASH "btn_set_cash"
#define LAB_CASH "lab_cash"
#define BTN_EXIT "btn_exit"
#define SBAR "sbar_main"
#define CHK_TIME_FT_DECIMAL "chk_time_ft_decimal"
#define CHK_CHEAT "chk_cheat"
#define CHK_RND_CHOOSE "chk_rnd_choose"


static const gchar *PRG_NAMES[] = {"prg_1","prg_2","prg_3","prg_4","prg_5","prg_6","prg_7","prg_8"};
static const gchar *LAB_TIME_NAMES[] = {"lab_time_1","lab_time_2","lab_time_3","lab_time_4",
					"lab_time_5","lab_time_6","lab_time_7","lab_time_8"};
static const gchar *IMG_NAMES[] = {"img_1","img_2","img_3","img_4","img_5","img_6","img_7","img_8"};
//选手名
static const gchar *RAD_STRINGS[] = {"孙悟空","周杰伦","钢铁侠","迈克乔丹","黄飞鸿",
					"蚁 人","成吉思汗","方世玉"};
static const gchar *RAD_NAMES[] = {"rad_1","rad_2","rad_3","rad_4","rad_5","rad_6","rad_7","rad_8"};
static const gchar *LAB_WIN_NAMES[] = {"lab_win_1","lab_win_2","lab_win_3","lab_win_4",
					"lab_win_5","lab_win_6","lab_win_7","lab_win_8"};

//选手排名1-8名
static int raking = 1;

typedef struct{
	GtkWidget *main_win;
	GtkBuilder *builder;
	GtkWidget *lab_cash;
	GtkWidget *btn_exit;
	GtkWidget *btn_run;
	GtkWidget *btn_set_cash;
	GtkWidget *sbar_main;
	GtkWidget *prgs[PERSON_COUNT];
	GtkWidget *lab_times[PERSON_COUNT];
	GtkWidget *imgs[PERSON_COUNT];
	GtkWidget *rads[PERSON_COUNT];
	GtkWidget *lab_wins[PERSON_COUNT];
	guint timers[PERSON_COUNT];
	GThread *threads[PERSON_COUNT];
	struct timeval tv_starts[PERSON_COUNT];
	struct timeval tv_ends[PERSON_COUNT];
	rec_t rec;
	int total_cash;
	int cash;
	bool is_all_rads_disabled;
	bool is_runing;
	bool is_time_ft_decimal;
	bool is_cheating;
	bool is_rnd_choose;
	//玩家选择的选手索引号
	int choosed_idx;
}app_context_t,*papp_context_t;

#define CUR_LAB_TIME(pic) (pic->pctx->lab_times[pic->idx])

//增加选手索引的ctx结构包装器
typedef struct{
	guint idx;
	papp_context_t pctx;
}idx_ctx_t,*pidx_ctx_t;

//设置所有rads的状态禁用或启用
void set_rads_status(papp_context_t pctx,bool st_enable){
	for(int i = 0;i < PERSON_COUNT;i++){
		if(st_enable)
			gtk_widget_set_sensitive(pctx->rads[i],TRUE);
		else
			gtk_widget_set_sensitive(pctx->rads[i],FALSE);
	}
}

//刷新显示状态栏
void refresh_sbar(papp_context_t pctx){
	GtkWidget *sbar = pctx->sbar_main;
	gchar *str = g_strdup_printf("total cash:%d\t\t\t\t\t\tbest sec:%s:%fs\t\t\t\t\t\tis_runing:%s",
		pctx->total_cash,RAD_STRINGS[pctx->rec.best_idx],
		pctx->rec.best_sec,pctx->is_runing?"YES":"NO");
	g_print("%s:str is %s\n",__func__,str);
	gtk_statusbar_push(GTK_STATUSBAR(sbar),gtk_statusbar_get_context_id(GTK_STATUSBAR(sbar),str),str);
}

//主窗口关闭按钮clicked触发回调
gboolean cb_delete(GtkWidget *self,GdkEvent *event,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	//如果比赛正在进行不能退出程序
	if(pctx->is_runing){
		GtkWidget *dlg = gnome_ok_dialog_parented("比赛正在进行...",
				GTK_WINDOW(pctx->main_win));
		gtk_window_set_modal(GTK_WINDOW(dlg),TRUE);
		return TRUE;
	}
	else{
		gtk_main_quit();
	}
	return FALSE;
}

//用户输入金额对话框确认或取消后的回调
void cb_after_set_cash(gchar *string,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	int cash = 0;
	bool invalid_cash = true;

	if(!string || strlen(string) == 0)
		g_print("%s:error string value!\n",__func__);
	else{
		if(1 != sscanf(string,"%d",&cash)){
			GtkWidget *dlg = gnome_ok_dialog_parented("must input number!!!",
				GTK_WINDOW(pctx->main_win));
			gtk_window_set_modal(GTK_WINDOW(dlg),TRUE);
		}else{
			if(cash < 1 || cash > 10000) goto _QUIT;
			pctx->cash = cash;
			gchar buf[256];
			snprintf(buf,256,"cash:%d",cash);
			gtk_label_set_text(GTK_LABEL(pctx->lab_cash),buf);
			invalid_cash = false;
		}
	}
_QUIT:
	if(invalid_cash){
		gtk_label_set_text(GTK_LABEL(pctx->lab_cash),"cash:INVALID");
		gtk_widget_set_sensitive(pctx->btn_run,FALSE);
	}
	else{
		gtk_widget_set_sensitive(pctx->btn_run,TRUE);
	}
}

//用户点击set money按钮后的回调
void cb_set_cash(GtkButton *btn,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	/*
	GtkWidget *dlg = gnome_request_string_dialog_parented("How much cash ? (1-10000)",
		(GnomeStringCallback)cb_after_set_cash,pctx,GTK_WINDOW(pctx->main_win));
	*/
	GtkWidget *dlg = gnome_request_dialog(FALSE,"How much cash ? (1-10000)",
		"5000",8,(GnomeStringCallback)cb_after_set_cash,pctx,GTK_WINDOW(pctx->main_win));
	gtk_window_set_modal(GTK_WINDOW(dlg),TRUE);
}

//显示每位选手历史最好成绩对话框
void cb_show_best_recs(GtkButton *btn,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	prec_t prec = &pctx->rec;

	gchar *buf = malloc(1024);
	buf[0] = '\0';
	snprintf(buf,1024,"\t%s 's %f sec is BEST SEC of all person\n\n",RAD_STRINGS[prec->best_idx],
		prec->best_sec);

	prec_sort_t rec_ary = db_rec_sort(&pctx->rec);
	guint len = 0;
	int idx;
	for(int i = 0;i < PERSON_COUNT;i++){
		len = strlen(buf);
		idx = rec_ary[i].idx;
		snprintf(buf + len,1024 - len,"[%d]\t%-20s\t 's best rec is %15.6f \t[total win %02d]\n",
			i+1,RAD_STRINGS[idx],prec->best_recs[idx],prec->win_counts[idx]);
	}

	free(rec_ary);

	/*
	guint len = 0;
	for(int i = 0;i < PERSON_COUNT;i++){
		len = strlen(buf);
		snprintf(buf+len,1024-len,"\t%s 's best rec is %f [total win %d]\n",RAD_STRINGS[i],
			prec->best_recs[i],prec->win_counts[i]);
	}
	buf[strlen(buf)] = '\0';
	printf("%s\n",buf);
	*/

	GtkWidget *dlg = gnome_ok_dialog_parented(buf,GTK_WINDOW(pctx->main_win));
	gtk_window_set_modal(GTK_WINDOW(dlg),TRUE);

	free(buf);
}

//#define DEV_RND_PATH "/dev/random"
//读取/dev/random设备会造成延时，遂使用urandom设备
#define DEV_RND_PATH "/dev/urandom"
//使用系统随机数文件产生随机数
int get_rnd_val_by_dev(void){
	FILE *hf = fopen(DEV_RND_PATH,"rb");
	if(!hf){
		g_print("%s:open %s failed!\n",__func__,DEV_RND_PATH);
		return -1;
	}

	int rnd_val = -1;
	if(1 != fread(&rnd_val,sizeof(rnd_val),1,hf)){
		g_print("%s:read %s failed!\n",__func__,DEV_RND_PATH);
		fclose(hf);
		return -1;
	}
	fclose(hf);
	return abs(rnd_val);
}

int get_rnd_val(uint tag){
	
	struct timeval tv;
	//以纳秒产生“足够随机”的种子
	gettimeofday(&tv,NULL);
	srandom(tv.tv_usec);
	return random();
}

//以当前时间填充timeval结构
void set_timeval_now(struct timeval *ptv){
	g_return_if_fail(ptv);
	gettimeofday(ptv,NULL);
}

//线程驱动游戏进程回调（当前未使用）
gpointer cb_thread(gpointer data){
	pidx_ctx_t pic = (pidx_ctx_t)data;
	guint idx = pic->idx;
	
	papp_context_t pctx = pic->pctx;
	GtkProgress *prg = GTK_PROGRESS(pctx->prgs[idx]);
	int v;
	
	while(TRUE){
		v = get_rnd_val_by_dev() % 100;
		g_print("[%p][%u] : v is %d\n",prg,idx,v);
		gfloat new_val = gtk_progress_get_value(prg) + v;
		g_print("[%p][%u] prg new_val is %f\n",prg,idx,new_val);
		GtkAdjustment *adj = prg->adjustment;

		gdk_threads_enter();

		if(new_val >= adj->upper) {
			new_val = adj->upper;
			gtk_progress_set_value(prg,new_val);
			g_print("[%u] will quit!\n",idx);
			g_free(data);
			gdk_threads_leave();
			break;
		}
		gtk_progress_set_value(prg,new_val);

		gdk_threads_leave();

		v = get_rnd_val_by_dev() % 2000000;
		g_print("[%p][%u] : v is %d\n",prg,idx,v);

		usleep(v);
	}
	
	//g_thread_exit(NULL);
	g_print("thread is quit!\n");
	return NULL;
}

//每场比赛结束后显示选手的名次
void show_raking_string(GtkWidget *rad,int idx,int raking){
	gchar buf[256];
	snprintf(buf,256,"%s (%d)",RAD_STRINGS[idx],raking);
	gtk_button_set_label(GTK_BUTTON(rad),buf);
}

//更新一位选手的最好秒数
void update_best_rec(papp_context_t pctx,int idx,double this_rec){
	double best_rec = pctx->rec.best_recs[idx];
	if(best_rec == 0.0 || this_rec < best_rec){
		pctx->rec.best_recs[idx] = this_rec;
		db_update(&pctx->rec);
	}
}

//更新rec记录中的最好记录
void update_best_sec(papp_context_t pctx,int idx,double this_sec){
	double best_sec = pctx->rec.best_sec;
	
	if(best_sec == 0 || this_sec < best_sec){
		pctx->rec.best_sec = this_sec;
		pctx->rec.best_idx = idx;
		db_update(&pctx->rec);
	}
}

//usec微妙 = 1000000秒
//msec毫秒 = 1000秒
//nsec纳秒 = 1000微妙
//计算指定选手比赛所耗秒数
double calc_match_sec(pidx_ctx_t pic){
	int idx = pic->idx;
	struct timeval *pstart_tv,*pend_tv;
	pstart_tv = &pic->pctx->tv_starts[idx]; 
	pend_tv = &pic->pctx->tv_ends[idx];
	double sec = ((pend_tv->tv_sec - pstart_tv->tv_sec)*1000000 + pend_tv->tv_usec - \
		pstart_tv->tv_usec)/1000000.0;
	return sec;
}

//显示选手的耗时秒数(小数方式显示)
void show_lab_time_string_with_decimal(pidx_ctx_t pic,double sec){
	int idx = pic->idx;
	GtkWidget *lab_time = pic->pctx->lab_times[idx]; 
	gchar buf[256];
	snprintf(buf,256,"%04.4f sec",sec);
	gtk_label_set_text(GTK_LABEL(lab_time),buf);
}

//显示选手的耗时秒数(电子表方式显示)
void show_lab_time_string_with_clock(pidx_ctx_t pic,double sec){
	//int idx = pic->idx;
	GtkWidget *lab_time = CUR_LAB_TIME(pic);
	gchar *str = get_clock_string(sec);
	gtk_label_set_text(GTK_LABEL(lab_time),str);
	g_free(str);
}

//显示选手耗时秒数的通用函数
void show_lab_time_string(pidx_ctx_t pic,double sec){
	if(pic->pctx->is_time_ft_decimal)
		show_lab_time_string_with_decimal(pic,sec);
	else
		show_lab_time_string_with_clock(pic,sec);
}

//刷新全部lab_time的显示格式
void refresh_lab_times(papp_context_t pctx){
	pidx_ctx_t pic = malloc(sizeof(idx_ctx_t));
	double sec = 0.0;
	pic->pctx = pctx;

	for(int i = 0;i < PERSON_COUNT;i++){
		pic->idx = i;
		sec = calc_match_sec(pic);
		show_lab_time_string(pic,sec);
	}
	free(pic);
}

gboolean prg_timeout(gpointer data){
	pidx_ctx_t pic = (pidx_ctx_t)data;
	papp_context_t pctx = pic->pctx;
	GtkProgress *prg = GTK_PROGRESS(pctx->prgs[pic->idx]);

	gfloat new_val;
	
	new_val = gtk_progress_get_value(prg) + get_rnd_val_by_dev() % 50;
	GtkAdjustment *adj = prg->adjustment;
	//如果选手已经跑到终点
	if(new_val >= adj->upper) {
		//new_val = adj->lower;
		new_val = adj->upper;

		//设置选手到达终点时间
		set_timeval_now(&pctx->tv_ends[pic->idx]);

		//将进度条显示到adj->upper
		gtk_progress_set_value(prg,new_val);

		//double sec = get_sec(pic);
		//计算选手耗时的秒数
		double sec = calc_match_sec(pic);
		//更新选手的最好成绩
		update_best_rec(pctx,pic->idx,sec);
		//在选手的lab_time中显示显示成绩
		show_lab_time_string(pic,sec);
		//设置选手到达图标
		gtk_image_set_from_stock(GTK_IMAGE(pctx->imgs[pic->idx]),\
			GTK_STOCK_OK,GTK_ICON_SIZE_BUTTON);
		//GtkWidget *rad = pctx->rads[pic->idx];
		//如果选手是第一名
		if(raking == 1){
			//增加赢的次数并更新数据库
			pctx->rec.win_counts[pic->idx]++;
			db_update(&pctx->rec);
			//更新记录中的最好成绩(全部选手中的)
			update_best_sec(pctx,pic->idx,sec);
			//更新显示选手的lab_win
			gchar buf[256];
			snprintf(buf,256,"赢%03d次",pctx->rec.win_counts[pic->idx]);
			gtk_label_set_text(GTK_LABEL(pctx->lab_wins[pic->idx]),buf);

			g_print("choosed_idx is %d , idx is %d\n",pctx->choosed_idx,pic->idx);
			//如果赌对了选手赢钱，错了输钱
			if(pctx->choosed_idx == pic->idx){
				GtkWidget *dlg = gnome_ok_dialog_parented("You choose is RIGHT!!!",
					GTK_WINDOW(pctx->main_win));
				gtk_window_set_modal(GTK_WINDOW(dlg),TRUE); 
				pctx->total_cash += pctx->cash;
			}else{
				pctx->total_cash -= pctx->cash;
			}
		}

		//如果是最后一名选手到达
		if(raking == 8){
			//设置比赛结束
			pctx->is_runing = false;
			//启用若干按钮
			gtk_widget_set_sensitive(pctx->btn_run,TRUE);
			gtk_widget_set_sensitive(pctx->btn_exit,TRUE);
			gtk_widget_set_sensitive(pctx->btn_set_cash,TRUE);
			//刷新状态栏
			refresh_sbar(pctx);
			//比赛完毕后，如果禁用rads，则重新启用它们
			if(pctx->is_all_rads_disabled){
				set_rads_status(pctx,true);
				pctx->is_all_rads_disabled = false;
			}

		}
		//显示选手名次
		GtkWidget *rad = pctx->rads[pic->idx];
		show_raking_string(rad,pic->idx,raking++);
		g_free(data);
		//退出定时器回调循环
		return G_SOURCE_REMOVE;
	}
	//选手还未到达终点
	//更新选手进度条显示
	gtk_progress_set_value(prg,new_val);
	//更新选手此次耗时
	set_timeval_now(&pctx->tv_ends[pic->idx]);
	//更新选手此次耗时显示
	double sec = calc_match_sec(pic);
	show_lab_time_string(pic,sec);
	
	//继续计时器回调循环
	return G_SOURCE_CONTINUE;
}

//使用数据库中的即赢场记录填充lab_wins标签
void refresh_lab_wins(papp_context_t pctx){
	gchar buf[256];
	for(int i = 0;i < PERSON_COUNT;i++){
		snprintf(buf,256,"赢%03d次",pctx->rec.win_counts[i]);
		gtk_label_set_text(GTK_LABEL(pctx->lab_wins[i]),buf);
	}
}

//刷新主窗口界面显示
void refresh_ui(papp_context_t pctx){
	//充值全局排名变量
	raking = 1;
	for(int i = 0;i < PERSON_COUNT;i++){
		//设置问号图片
		gtk_image_set_from_stock(GTK_IMAGE(pctx->imgs[i]),\
			GTK_STOCK_DIALOG_QUESTION,GTK_ICON_SIZE_BUTTON);
		//将进度条显示归零
		gtk_progress_set_value(GTK_PROGRESS(pctx->prgs[i]),0);
		//重置显示选手名字
		gtk_button_set_label(GTK_BUTTON(pctx->rads[i]),RAD_STRINGS[i]);
	}
	//刷新赢次标签
	refresh_lab_wins(pctx);
}

//RUN！按钮clicked回调
void start_run(GtkButton *btn,gpointer data){
	papp_context_t pctx = (papp_context_t)data;

	refresh_ui(pctx);

	//开始比赛
	pctx->is_runing = true;
	//根据是否启用作弊更改rads的状态
	if(!pctx->is_cheating){
		set_rads_status(pctx,false);
		pctx->is_all_rads_disabled = true;
	}else{
		set_rads_status(pctx,true);
		pctx->is_all_rads_disabled = false;
	}

	//如果设置随机选择，则随机选择一个rad
	if(pctx->is_rnd_choose){
		int rnd_idx = get_rnd_val_by_dev() % 8;
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pctx->rads[rnd_idx]),TRUE);
	}

	//每位选手添加定时器回调
	for(int i = 0;i < PERSON_COUNT;i++){
		pidx_ctx_t pic = g_malloc0(sizeof(idx_ctx_t));
		pic->pctx = pctx;
		pic->idx = i;
		set_timeval_now(&pctx->tv_starts[i]);
		pctx->timers[i] = g_timeout_add(50,prg_timeout,pic);
		//pctx->threads[i] = g_thread_new(NULL,cb_thread,pto);
	}
	//将一些按钮设为禁用
	gtk_widget_set_sensitive(GTK_WIDGET(btn),FALSE);
	gtk_widget_set_sensitive(pctx->btn_exit,FALSE);
	gtk_widget_set_sensitive(pctx->btn_set_cash,FALSE);
	refresh_sbar(pctx);
}

//随机选择按钮回调函数
void cb_rnd_choose(GtkWidget *self,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	pctx->is_rnd_choose = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self));
}

//作弊按钮回调函数
void cb_cheat_toggled(GtkWidget *self,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	
	pctx->is_cheating = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self));
	//运行时动态修改rads的状态
	if(pctx->is_cheating && pctx->is_runing){
		set_rads_status(pctx,true);
		pctx->is_all_rads_disabled = false;
	}else if(!pctx->is_cheating && pctx->is_runing){
		set_rads_status(pctx,false);
		pctx->is_all_rads_disabled = true;
	}
}

//选择时间格式按钮回调函数
void cb_time_ft_toggled(GtkWidget *self,gpointer data){
	papp_context_t pctx = (papp_context_t)data;
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(self)))
		pctx->is_time_ft_decimal = true;
	else
		pctx->is_time_ft_decimal = false;
	refresh_lab_times(pctx);
}

//用户选择选手时回调函数
void cb_rad_toggled(GtkWidget *rad,gpointer data){
	//ptimeout_t pto = (ptimeout_t)data;
	pidx_ctx_t pic = (pidx_ctx_t)data;
	papp_context_t pctx = pic->pctx;
	int idx = pic->idx;

	//如果radio按钮被按下（别的按钮被按下后，本按钮也会产生toggled回调，所以要
	//排除这种情况）则设置pctx中的choosed_idx变量。
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(rad))){
		g_print("%s:idx %d rad is clicked!\n",__func__,idx);
		pctx->choosed_idx = idx;
	}
}

//初始化radio按钮
void init_rads(papp_context_t pctx){
	GtkWidget *rad;
	for(int i = 0;i < PERSON_COUNT;i++){
		//ptimeout_t pto = g_malloc0(sizeof(timeout_t));
		pidx_ctx_t pic = g_malloc0(sizeof(idx_ctx_t));
		pic->pctx = pctx;
		pic->idx = i;

		rad = GTK_WIDGET(gtk_builder_get_object(pctx->builder,RAD_NAMES[i]));
		gtk_signal_connect(GTK_OBJECT(rad),"toggled",G_CALLBACK(cb_rad_toggled),pic);
	}
}

//返回图片文件表示的pixbuf对象
GdkPixbuf *create_pixbuf(const gchar *path){
	GdkPixbuf *pixbuf;
	GError *error = NULL;
	pixbuf = gdk_pixbuf_new_from_file(path,&error);
	if(!pixbuf){
		fprintf(stderr, "%s\n", error->message);
		g_error_free(error);
	}
	return pixbuf;
}

void init_win_main(papp_context_t pctx){
	pctx->main_win = GTK_WIDGET(gtk_builder_get_object(pctx->builder,MAIN_WINDOW));
	if(!pctx->main_win)
		g_critical("Widget %s is missing in file %s",MAIN_WINDOW,UI_PATH);

	gtk_window_set_resizable(GTK_WINDOW(pctx->main_win),FALSE);
	gtk_window_set_title(GTK_WINDOW(pctx->main_win),"RUN GAME 2015");
	gtk_window_set_position(GTK_WINDOW(pctx->main_win),GTK_WIN_POS_CENTER_ALWAYS);
	gtk_container_set_border_width(GTK_CONTAINER(pctx->main_win),5);
	gtk_widget_set_size_request(pctx->main_win,800,400);
	gtk_window_set_icon(GTK_WINDOW(pctx->main_win),create_pixbuf("main48.png"));

	gtk_signal_connect(GTK_OBJECT(pctx->main_win),"delete_event",G_CALLBACK(cb_delete),pctx);

	GtkWidget *chk_time_ft = GTK_WIDGET(gtk_builder_get_object(
		pctx->builder,CHK_TIME_FT_DECIMAL));
	gtk_signal_connect(GTK_OBJECT(chk_time_ft),"toggled",G_CALLBACK(cb_time_ft_toggled),pctx);

	GtkWidget *btn_best = GTK_WIDGET(gtk_builder_get_object(pctx->builder,BTN_BEST));
	gtk_signal_connect(GTK_OBJECT(btn_best),"clicked",G_CALLBACK(cb_show_best_recs),pctx);

	GtkWidget *chk_rnd_choose = GTK_WIDGET(gtk_builder_get_object(
		pctx->builder,CHK_RND_CHOOSE));
	gtk_signal_connect(GTK_OBJECT(chk_rnd_choose),"toggled",G_CALLBACK(cb_rnd_choose),pctx);
}

void init_ctx_widgets(papp_context_t pctx){
	g_return_if_fail(pctx);

	pctx->total_cash = 1000000;
	pctx->is_time_ft_decimal = false;
	pctx->is_cheating = false;
	pctx->is_all_rads_disabled = false;
	pctx->is_rnd_choose = false;

	init_win_main(pctx);

	for(int i = 0;i < PERSON_COUNT;i++){
		//设置选手比赛进度条的
		GtkAdjustment *adj = (GtkAdjustment*)gtk_adjustment_new(0,1,5000,0,0,0);
		//ptimeout_t pto = g_malloc0(sizeof(timeout_t));
		pctx->prgs[i] = GTK_WIDGET(gtk_builder_get_object(pctx->builder,PRG_NAMES[i]));
		pctx->lab_times[i] = GTK_WIDGET(gtk_builder_get_object(pctx->builder,LAB_TIME_NAMES[i]));
		pctx->imgs[i] = GTK_WIDGET(gtk_builder_get_object(pctx->builder,IMG_NAMES[i]));
		pctx->rads[i] = GTK_WIDGET(gtk_builder_get_object(pctx->builder,RAD_NAMES[i]));
		pctx->lab_wins[i] = GTK_WIDGET(gtk_builder_get_object(pctx->builder,LAB_WIN_NAMES[i]));

		gtk_widget_set_size_request(pctx->prgs[i],400,20);
		//GTK_PROGRESS(pctx->prgs[i])->adjustment = adj;
		//gtk_progress_set_adjustment(GTK_PROGRESS(pctx->prgs[i]),adj);
		//下面一句代码可以用上面一句代码代替
		g_object_set(pctx->prgs[i],"adjustment",adj,NULL);
	}

	refresh_lab_wins(pctx);

	pctx->lab_cash = GTK_WIDGET(gtk_builder_get_object(pctx->builder,LAB_CASH));
	pctx->btn_exit = GTK_WIDGET(gtk_builder_get_object(pctx->builder,BTN_EXIT));

	pctx->btn_set_cash = GTK_WIDGET(gtk_builder_get_object(pctx->builder,BTN_SET_CASH));
	gtk_signal_connect(GTK_OBJECT(pctx->btn_set_cash),"clicked",G_CALLBACK(cb_set_cash),pctx);

	pctx->sbar_main = GTK_WIDGET(gtk_builder_get_object(pctx->builder,SBAR));
	refresh_sbar(pctx);

	pctx->btn_run = GTK_WIDGET(gtk_builder_get_object(pctx->builder,BTN_RUN));
	gtk_signal_connect(GTK_OBJECT(pctx->btn_run),"clicked",G_CALLBACK(start_run),pctx);
	gtk_widget_set_sensitive(pctx->btn_run,FALSE);

	GtkWidget *chk_cheat = GTK_WIDGET(gtk_builder_get_object(pctx->builder,CHK_CHEAT));
	gtk_signal_connect(GTK_OBJECT(chk_cheat),"toggled",G_CALLBACK(cb_cheat_toggled),pctx);

	//((GtkProgressBar*)pctx->prgs[0])->adjustment = adj;
	//GtkAdjustment *adj_get = NULL;
	//g_object_set_data(G_OBJECT(pctx->prgs[0]),"adjustment",adj);
	
	//g_object_get(pctx->prgs[0],"adjustment",&adj_get,NULL);
	//g_print("%s:prgs %p 's adj_get is %p\n",__func__,pctx->prgs[0],adj_get);
	
}

bool init_rec(prec_t prec){
	return db_read(prec);
}

void test_rnd(void){
	for(int i = 0;i < 100;i++){
		printf("[%d]: %d %d\n",i,get_rnd_val(i),get_rnd_val_by_dev());
		//printf("[%d] : %d\n",i,get_rnd_val_by_dev());
		//printf("[%d]: %d %d\n",i,i*i,i*i+1);
	}
}

int main(int argc,char **argv){
	GError *error = NULL;
	papp_context_t pctx = g_malloc0(sizeof(app_context_t));
	
	//若希望启用gdk的线程支持需要启用下面一段注释代码
	/*
	if(!g_thread_supported()) {
		//g_thread_init(NULL);
		g_print("%s:WARNING : no thread supported!?\n",__func__);
	}

	gdk_threads_init();
	*/

	gtk_init(&argc,&argv);
	GtkBuilder *builder = gtk_builder_new();
	if(!gtk_builder_add_from_file(builder,UI_PATH,&error)){
		g_critical("Couldn't load builder file : %s",error->message);
		g_error_free(error);
	}
	pctx->builder = builder;
	/*
	if(!gtk_window_set_default_icon_from_file("main48.png",&error)){
		g_print("%s:set default icon failed duo to : %s\n",__func__,error->message);
	}
	
	if(!gtk_window_set_icon_from_file(GTK_WINDOW(pctx->main_win),"main.jpg",&error)){
		g_print("%s:set app icon failed duo to : %s\n",__func__,error->message);
	}
	*/

	//db_clear();
	init_rec(&pctx->rec);
	init_ctx_widgets(pctx);
	init_rads(pctx);

	gtk_builder_connect_signals(builder,NULL);
	g_object_unref(builder);

	gtk_widget_show_all(pctx->main_win);

	test_rnd();

	//在其他非主线程更新GUI元素的时候需要打开以下2句注释以同步操作
	//gdk_threads_enter();
	gtk_main();
	//gdk_threads_leave();

	g_free(pctx);
	return 0;
}
